package com.zhanghu.backendZray.manager.alipay;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zhanghu.backendZray.cache.ContextCache;
import com.zhanghu.backendZray.constants.CommonConstant;
import com.zhanghu.backendZray.enums.SaleOrderStatusEnum;
import com.zhanghu.backendZray.exception.ApiException;
import com.zhanghu.backendZray.manager.property.PropertyManager;
import com.zhanghu.backendZray.manager.role.UserRoleMenuManager;
import com.zhanghu.backendZray.pojo.entity.Member;
import com.zhanghu.backendZray.pojo.entity.SaleOrder;
import com.zhanghu.backendZray.pojo.entity.User;
import com.zhanghu.backendZray.pojo.entity.UserRole;
import com.zhanghu.backendZray.service.MemberService;
import com.zhanghu.backendZray.service.SaleOrderService;
import com.zhanghu.backendZray.service.UserRoleService;
import com.zhanghu.backendZray.utils.saleOrder.SaleOrderUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author ZhangDong
 * @date 2024/8/9 16:30
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AlipayManager {
    private final PropertyManager propertyManager;
    private final SaleOrderService saleOrderService;
    private final MemberService memberService;
    private final UserRoleService userRoleService;
    private final UserRoleMenuManager userRoleMenuManager;

    /**
     * 当面付预下订单
     */
    @Transactional(rollbackFor = Exception.class)
    public byte[] tradePrecreate() throws IOException {
//        AssertUtils.notEmpty(requestDTO.getSubject(), "标题不可以为空");
//        AssertUtils.notEmpty(requestDTO.getTotalAmount(), "金额不可以为空");
//        AssertUtils.check(requestDTO.getSubject().length() > 50, "标题不可以超过50字");
//        AssertUtils.check(requestDTO.getTotalAmount().compareTo(new BigDecimal("0")) <= 0, "金额需要大于0元");
//        AssertUtils.check(requestDTO.getTotalAmount().compareTo(new BigDecimal(50)) >= 0, "金额不可以超过50元");
        // 创建 AlipayClient
        Integer currentUserId = ContextCache.currentUserId();
        String orderNo = SaleOrderUtil.generateOrderNo();
        BigDecimal amount = CommonConstant.MEMBER_PRICE;
        String subject = "乐集网支付";

        // 移除当前用户前面未支付的订单
        saleOrderService.remove(new LambdaQueryWrapper<SaleOrder>().eq(SaleOrder::getUserId, currentUserId)
                .eq(SaleOrder::getStatus, SaleOrderStatusEnum.UNPAID.getStatus()));
        SaleOrder saleOrder = new SaleOrder();
        saleOrder.setOrderNo(orderNo);
        saleOrder.setAmount(amount);
        saleOrder.setUserId(currentUserId);
        saleOrderService.save(saleOrder);
        AlipayClient alipayClient = new DefaultAlipayClient(
                CommonConstant.ALIPAY_SERVER_URL,
                propertyManager.getAlipayAppId(),
                propertyManager.getAlipayPrivateKey(),
                "json",
                CharsetUtil.UTF_8,
                propertyManager.getAlipayPublicKey(),
                "RSA2");
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        request.setBizContent(String.format("{\n"
                        + "    \"out_trade_no\": \"%s\", \n"
                        + "    \"total_amount\": \"%s\", \n"
                        + "    \"subject\": \"%s\", \n"
                        + "    \"store_id\": \"JM01\", \n"
                        + "    \"qr_code_timeout_express\": \"30m\"\n"
                        + "}",
                orderNo,
                amount.setScale(2, RoundingMode.HALF_UP),
                subject
        ));
        request.setNotifyUrl(propertyManager.getAlipayNotifyUrl());
        AlipayTradePrecreateResponse response;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            throw new ApiException(String.format("下单失败 错误代码:[%s], 错误信息:[%s]", e.getErrCode(), e.getErrMsg()));
        }
        log.info("Alipay trade-precreate Response = {}", response.getBody());
        if (!response.isSuccess()) {
            throw new ApiException(String.format("下单失败 错误代码:[%s], 错误信息:[%s]", response.getCode(), response.getMsg()));
        }
        // 生成支付二维码图片
        int width = 137 + 12 * (7 - 1);
        int height = 137 + 12 * (7 - 1);
        BufferedImage image = QrCodeUtil.generate(response.getQrCode(), width, height);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(image, "jpeg", out);
        byte[] b = out.toByteArray();
        out.write(b);
        out.close();
        return b;
    }

    /**
     * 支付宝官方支付回调（扫码支付）
     */
    @Transactional(rollbackFor = Exception.class)
    public String tradeNotify(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        Map<String, String> params = new HashMap<>(32);
        parameterMap.forEach((key, val) -> params.put(key, String.join(",", val)));
        log.info("alipay trade-notify params:{}", JSON.toJSONString(params));
        try {
            // 必须要验签
            boolean check = AlipaySignature.rsaCheckV1(params, propertyManager.getAlipayPublicKey(), CharsetUtil.UTF_8, "RSA2");
            if (!check) {
                return "rsaCheckV1 = false";
            }
        } catch (Exception e) {
            log.error("alipay trade-notify, exception:", e);
            return "failure";
        }
        // 修改下单的订单信息为已支付
        String tradeNo = params.get("out_trade_no");
        SaleOrder saleOrder = saleOrderService.getOne(new LambdaQueryWrapper<SaleOrder>().eq(SaleOrder::getOrderNo, tradeNo));
        Assert.notNull(saleOrder, "订单不存在:" + tradeNo);
        saleOrder.setStatus(SaleOrderStatusEnum.PAID.getStatus());
        saleOrderService.updateById(saleOrder);
        // 新增会员
        Member member = new Member();
        member.setAmount(saleOrder.getAmount());
        member.setUserId(saleOrder.getUserId());
        member.setExpiryDateEnd(LocalDate.now().plusYears(1L));
        memberService.save(member);
        // 移除该人员的旧权限
        userRoleService.remove(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, saleOrder.getUserId()));
        // 为会员新增菜单权限
        userRoleMenuManager.addMemberRole(saleOrder.getUserId());
        return "success";
    }

    /**
     * 当前用户最近的一笔订单是否已支付
     */
    public boolean latestTradeStatusGet() {
        Integer currentUserId = ContextCache.currentUserId();
        Optional<SaleOrder> first = saleOrderService.list(new LambdaQueryWrapper<SaleOrder>().eq(SaleOrder::getUserId, currentUserId)
                .orderByDesc(SaleOrder::getId)).stream().findFirst();
        AtomicBoolean success = new AtomicBoolean(false);
        first.map(SaleOrder::getStatus).ifPresent(r -> {
            if (SaleOrderStatusEnum.PAID.getStatus().equals(r)) {
                success.set(true);
            }
        });
        return success.get();
    }
}
